package com.dd.cloud.user.service.chknowl.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.constants.ChKnowlConstants;
import com.dd.cloud.user.entity.chknowl.ChknowlChDrugsCategory;
import com.dd.cloud.user.entity.chknowl.ChknowlCurr;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.user.entity.chknowl.ChknowlCurrCategory;
import com.dd.cloud.user.mapper.chknowl.ChknowlCurrMapper;
import com.dd.cloud.user.req.chknowl.*;
import com.dd.cloud.user.res.chknowl.ChUserSearchListRes;
import com.dd.cloud.user.res.chknowl.ChknowlCurrPageRes;
import com.dd.cloud.user.res.chknowl.ChknowlCurrRes;
import com.dd.cloud.user.service.chknowl.IChknowlCurrCategoryService;
import com.dd.cloud.user.service.chknowl.IChknowlCurrService;
import com.dd.cloud.user.service.search.ISearchHotService;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.utils.ExtUtils;
import com.dd.cloud.common.utils.ObjectUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 通方表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-07-04
 */
@Service
@Slf4j
public class ChknowlCurrServiceImpl extends ServiceImpl<ChknowlCurrMapper, ChknowlCurr> implements IChknowlCurrService {
    @Autowired
    private ISearchHotService searchHotService;


    @Autowired
    private IChknowlCurrCategoryService chknowlCurrCategoryService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private String currKey = "chknow-curr-all";


    /**
     * 导入excel文档 经验方数据
     *
     * @param file
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importPresCurrFromExcel(MultipartFile file) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        try {
            List<ChknowlCurr> list = ExtUtils.importExcel(file, 0, 1, ChknowlCurr.class);
            list.stream().forEach(curr -> {
                curr.setCreateDate(LocalDateTime.now());
                curr.setStatus(ChKnowlConstants.ContentStatus.NORMAL);
//                curr.setOperDate(LocalDateTime.now());
//                curr.setOperId(loginInfo.getId());
            });
            boolean j = saveBatch(list);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导出经验方数据到excel
     */
    @Override
    public void exportPresCurrtoExcel(HttpServletResponse response) {
        List<ChknowlCurr> list = list();
        try {
            ExtUtils.exportExcel(list, "经验方", "1", ChknowlCurr.class, "经验方.xls", response);
        } catch (IOException e) {

        }
    }

    /**
     * 分页获取经验方
     *
     * @param req
     * @return
     */
    @Override
    public Page<ChknowlCurrPageRes> getExperByPage(CurrListPageReq req) {
        Page<ChknowlCurrPageRes> page = req.pagePojo();
        page = getBaseMapper().getChknowCurrPage(page, req);
//        if (!StringUtils.isBlank(req.getKeyword())) {
//            searchHotService.saveSearchHot(SearchConstants.Modular.CHSCIENCE, SearchConstants.ChscienceSubmodule.CURR, req.getKeyword());
//        }
        return page;
    }

    /**
     * 添加经验方
     *
     * @param req
     */
    @Override
    public void createExper(ChknowlCurrCreateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        if (!ObjectUtils.refrect(ChKnowlConstants.ContentStatus.class, req.getStatus())) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        ChknowlCurr md = new ChknowlCurr();
        BeanUtils.copyProperties(req, md);
        md.setCreateDate(LocalDateTime.now());
//        md.setOperDate(LocalDateTime.now());
//        md.setOperId(loginInfo.getId());
        boolean flag = save(md);
        if (!flag) {
            throw new ZekeException(400, "添加经验方信息失败");
        }
    }

    /**
     * 修改经验方
     *
     * @param req
     */
    @Override
    public void updateExper(ChknowlCurrUpdateReq req) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        ChknowlCurr mpd = getById(req.getId());
        if (mpd == null || mpd.getStatus() == ChKnowlConstants.ContentStatus.DELETE) {
            throw new ZekeException(400, "经验方信息不存在");
        }
        if (!ObjectUtils.refrect(ChKnowlConstants.ContentStatus.class, req.getStatus())) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        BeanUtils.copyProperties(req, mpd);
//        mpd.setOperId(loginInfo.getId());
//        mpd.setOperDate(LocalDateTime.now());
        boolean flag = updateById(mpd);
        if (!flag) {
            throw new ZekeException(400, "修改医案信息失败");
        }
    }

    /**
     * 批量修改经验方状态
     *
     * @param ids
     * @param status
     */
    @Override
    public void updateBatchStatus(String ids, Integer status) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo(LoginInfo.UserType.ADMIN).get();
        if (!ObjectUtils.refrect(ChKnowlConstants.ContentStatus.class, status)) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        List list = new ArrayList();
        if (ids.indexOf(",") >= 0) {
            String[] ary = ids.split(",");
            for (String s : ary) {
                list.add(s);
            }
        } else {
            list.add(ids);
        }
        UpdateWrapper<ChknowlCurr> uw = new UpdateWrapper<>();
        uw.lambda().in(ChknowlCurr::getId, list);
        ChknowlCurr presCurr = new ChknowlCurr();
        presCurr.setStatus(status);
//        presCurr.setOperId(loginInfo.getId());
//        presCurr.setOperDate(LocalDateTime.now());
        boolean i = update(presCurr, uw);
        if (!i) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }

    /**
     * 关键字搜索经验方
     *
     * @param keyword
     * @return
     */
    @Override
    public List<ChUserSearchListRes> queryPresCurrByKeyword(String keyword) {
        return null;
    }

    /**
     * 通过id获取通方
     *
     * @param id
     * @return
     */
    @Override
    public ChknowlCurr getPresCurrById(Integer id) {
        return getById(id);
    }


    @Override
    public List<ChknowlCurrRes> queryOftenCurrList() {
        String result = redisTemplate.opsForValue().get(currKey);
        if (StringUtils.isNotBlank(result)) {
            List<ChknowlCurrRes> chknowlCurrRes = JSON.parseObject(result, List.class);
            return chknowlCurrRes;
        } else {
            List<ChknowlCurrRes> res = this.getBaseMapper().queryCategoryList();
            List<ChknowlCurr> chknowlCurrs = this.getBaseMapper().queryOftenCurrList();
            if (CollectionUtil.isNotEmpty(res)) {
                Map<Integer, List<ChknowlCurr>> currMap = getCurrsList(chknowlCurrs);
                if (CollectionUtil.isNotEmpty(res)) {
                    for (ChknowlCurrRes item : res) {
                        List<ChknowlCurrRes> childList = item.getChknowlCurrChild();
                        if (CollectionUtil.isNotEmpty(childList)) {
                            item.setIsChild(true);
                            for (ChknowlCurrRes child : childList) {
                                List<ChknowlCurr> chknowlCurrList = currMap.get(child.getCategoryId());
                                child.setChknowlCurrList(chknowlCurrList);
                                child.setIsChild(false);
                            }
                        } else {
                            item.setIsChild(false);
                            List<ChknowlCurr> chknowlCurrList = currMap.get(item.getCategoryId());
                            item.setChknowlCurrList(chknowlCurrList);
                        }
                    }
                }
            }
            redisTemplate.opsForValue().set(currKey, JSON.toJSONString(res));
            return res;
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importCurrBatch(MultipartFile file) {
        if (file == null) {
            throw new ZekeException(400, "请上传文件");
        }
        if (!file.getOriginalFilename().contains(".xlsx") && !file.getOriginalFilename().contains(".xls")) {
            throw new ZekeException(400, "只支持xlsx和xls文件格式");
        }
        List<ExcelAddCurrModel> list = new ArrayList<>();
        try {
            list = ExtUtils.importExcel(file, 0, 1, ExcelAddCurrModel.class);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ZekeException(400, "解析Excel失败");
        }

        if (list == null || list.isEmpty()) {
            throw new ZekeException(400, "文档数据为空");
        }
        List<ChknowlCurr> currList = new ArrayList<>();
        for (ExcelAddCurrModel model : list) {
            String category = model.getCategory();
            String[] categories = category.split("-");
            Integer categoryId = null;
            if (categories.length == 1) {
                //一级
                categoryId = queryCurrOneCategoryId(categories);
            } else if (categories.length == 2) {
                //一级
                categoryId = queryCurrOneCategoryId(categories);
                //二级
                categoryId = queryCurrTwoCategoryId(categories, categoryId);
            }
            ChknowlCurr newCurr = new ChknowlCurr();
            BeanUtils.copyProperties(model, newCurr);
            newCurr.setCreateDate(LocalDateTime.now())
                    .setStatus(1)
                    .setSource(model.getSource())
                    .setCategoryId(categoryId);
            String type = model.getType();
            if (type.equals("正方")) {
                newCurr.setType(1);
            } else if (type.equals("附方")) {
                newCurr.setType(2);
            }
            currList.add(newCurr);
        }
        if (CollectionUtil.isNotEmpty(currList)) {
            boolean flag = this.saveBatch(currList);
            if (!flag) {
                throw new ZekeException("~保存失败~");
            }
            redisTemplate.delete(currKey);
        }
    }

    private Integer queryCurrTwoCategoryId(String[] categories, Integer categoryId) {
        LambdaQueryWrapper<ChknowlCurrCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChknowlCurrCategory::getName, categories[1])
                .eq(ChknowlCurrCategory::getStatus, 1)
                .eq(ChknowlCurrCategory::getLevel, 2)
                .last("limit 1");
        ChknowlCurrCategory chknowlChDrugsCategory = chknowlCurrCategoryService.getOne(wrapper);
        //不存在这个分类名保存一条
        if (chknowlChDrugsCategory == null) {
            ChknowlCurrCategory newCategory = new ChknowlCurrCategory();
            newCategory
                    .setName(categories[1])
                    .setLevel(2)
                    .setCreateDate(LocalDateTime.now())
                    .setPid(categoryId)
                    .setStatus(1);
            LambdaQueryWrapper<ChknowlCurrCategory> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ChknowlCurrCategory::getStatus, 1)
                    .eq(ChknowlCurrCategory::getLevel, 2)
                    .eq(ChknowlCurrCategory::getPid, categoryId)
                    .orderByDesc(ChknowlCurrCategory::getSort)
                    .last("limit 1");
            ChknowlCurrCategory currCategory = chknowlCurrCategoryService.getOne(queryWrapper);
            if (currCategory == null) {
                newCategory.setSort(1);
            } else {
                newCategory.setSort(currCategory.getSort() + 1);
            }
            chknowlCurrCategoryService.save(newCategory);
            categoryId = newCategory.getId();
        } else {
            categoryId = chknowlChDrugsCategory.getId();
        }
        log.info("分类id:{}", categoryId);
        return categoryId;
    }

    private Integer queryCurrOneCategoryId(String[] categories) {
        Integer categoryId = null;
        LambdaQueryWrapper<ChknowlCurrCategory> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ChknowlCurrCategory::getName, categories[0])
                .eq(ChknowlCurrCategory::getStatus, 1)
                .eq(ChknowlCurrCategory::getLevel, 1)
                .last("limit 1");
        ChknowlCurrCategory chknowlCurrCategory = chknowlCurrCategoryService.getOne(wrapper);
        //不存在这个分类名保存一条
        if (chknowlCurrCategory == null) {
            ChknowlCurrCategory newCategory = new ChknowlCurrCategory();
            newCategory
                    .setName(categories[0])
                    .setLevel(1)
                    .setCreateDate(LocalDateTime.now())
                    .setPid(0)
                    .setStatus(1);
            LambdaQueryWrapper<ChknowlCurrCategory> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ChknowlCurrCategory::getStatus, 1)
                    .eq(ChknowlCurrCategory::getLevel, 1)
                    .eq(ChknowlCurrCategory::getPid, 0)
                    .orderByDesc(ChknowlCurrCategory::getSort)
                    .last("limit 1");
            ChknowlCurrCategory currCategory = chknowlCurrCategoryService.getOne(queryWrapper);
            if (currCategory == null) {
                newCategory.setSort(1);
            } else {
                newCategory.setSort(currCategory.getSort() + 1);
            }
            chknowlCurrCategoryService.save(newCategory);
            categoryId = newCategory.getId();
        } else {
            categoryId = chknowlCurrCategory.getId();
        }
        log.info("分类id:{}", categoryId);
        return categoryId;
    }

    private Map<Integer, List<ChknowlCurr>> getCurrsList(List<ChknowlCurr> chknowlCurrs) {
        if (CollectionUtil.isNotEmpty(chknowlCurrs)) {
            return chknowlCurrs.stream().collect(Collectors.groupingBy(ChknowlCurr::getCategoryId));
        }
        return new HashedMap();
    }

    private Map<Integer, List<ChknowlCurrCategory>> getChildList(List<ChknowlCurrCategory> categories) {
        Map<Integer, List<ChknowlCurrCategory>> map = categories.stream().filter(item -> item.getPid() != 0).collect(Collectors.groupingBy(ChknowlCurrCategory::getPid));
        if (CollectionUtil.isNotEmpty(map)) {
            return new HashedMap();
        }
        return map;
    }

    private List<ChknowlCurrCategory> getParentList(List<ChknowlCurrCategory> categories) {
        return categories.stream().filter(item -> item.getPid() == 0).collect(Collectors.toList());
    }
}
